package com.example.testdemo.db.sql;

import android.database.Cursor;

import com.example.testdemo.db.reflex.Reflex;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *
 * </p>
 *
 * @author 永健
 * @since 2020-03-28 18:38
 */
public class ResultHandler<T> {

    private static final String SELECT = "select";
    private static final String WHERE = "where";
    private static final String FROM = "from";
    private static final String SPACE = " ";
    private static final String AS = "as";
    private static final String COMMA = ",";

    private Class<T> aClass;

    public ResultHandler(Class<T> t) {
        this.aClass = t;
    }

    public <T> List<T> resultEntity(String sql, Cursor cursor) {
        List<String> list = paraSqlGetColumn(sql);
        List<T> tList = new ArrayList<>();

        try {
            Constructor<?> constructor = aClass.getDeclaredConstructor();
            constructor.setAccessible(true);

            cursor.moveToFirst();
            while (!cursor.isAfterLast()) {
                Object instance = aClass.newInstance();
                for (int i = 0; i < list.size(); i++) {
                    String name = list.get(i);
                    String nameSource = name.contains(COMMA) ? name.split(COMMA)[0] : name;
                    String mapKey = name.contains(COMMA) ? name.split(COMMA)[1] : "";
                    if (mapKey.equals("")) {
                        mapKey = nameSource;
                    }

                    Field field = aClass.getDeclaredField(name);
                    field.setAccessible(true);

                    Class<?> type = field.getType();

                    if (type == Integer.class) {
                        field.set(instance, cursor.getInt(i));
                    } else if (type == Long.class) {
                        field.set(instance, cursor.getLong(i));
                    } else if (type == String.class) {
                        field.set(instance, cursor.getString(i));
                    } else if (type == Double.class) {
                        field.set(instance, cursor.getDouble(i));
                    } else if (type == Float.class) {
                        field.set(instance, cursor.getFloat(i));
                    } else if (type == byte[].class) {
                        field.set(instance, cursor.getBlob(i));
                    }
                }
                tList.add((T) instance);
                cursor.moveToNext();
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return tList;
    }

    public List<Map<String, Object>> resultMap(String sql, Cursor cursor) {
        List<String> list = paraSqlGetColumn(sql);
        List<Map<String, Object>> maps = new ArrayList<>();

        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            Map<String, Object> map = new HashMap<>();
            for (int i = 0; i < list.size(); i++) {
                String name = list.get(i);
                String nameSource = name.contains(COMMA) ? name.split(COMMA)[0] : name;
                String mapKey = name.contains(COMMA) ? name.split(COMMA)[1] : "";
                if (mapKey.equals("")) {
                    mapKey = nameSource;
                }
                Class<?> type = Reflex.getFieldType(aClass, nameSource);
                if (type == Integer.class) {
                    map.put(mapKey, cursor.getInt(i));
                } else if (type == Long.class) {
                    map.put(mapKey, cursor.getLong(i));
                } else if (type == String.class) {
                    map.put(mapKey, cursor.getString(i));
                } else if (type == Double.class) {
                    map.put(mapKey, cursor.getDouble(i));
                } else if (type == Float.class) {
                    map.put(mapKey, cursor.getFloat(i));
                } else if (type == byte[].class) {
                    map.put(mapKey, cursor.getBlob(i));
                }
            }
            maps.add(map);
            cursor.moveToNext();
        }

        return maps;
    }

    private static List<String> paraSqlGetColumn(String sql) {
        //String sql = "select c.name as n,n.id nId from   tb_name   n  where id = 1";
        List<String> strings = new ArrayList<>();
        sql = sql.toLowerCase().trim();

        int from = sql.indexOf(FROM);
        int where = sql.indexOf(WHERE);

        // 截取表名字
        if (where < 0) {
            where = sql.length();
        }


        // 表名字
        String tableNameTemp = sql.substring(from + FROM.length(), where).trim();
        String tableAlias = "";
        String tableName = "";


        // 截取 select 的所有字段
        String column = sql.substring(SELECT.length(), from);

        // 是否查询所有字段
        int of = tableNameTemp.toLowerCase().indexOf(AS);
        if (of > 0) {
            tableName = tableNameTemp.substring(0, of).replaceAll(SPACE, "");
            tableAlias = tableNameTemp.substring(of + AS.length()).replaceAll(SPACE, "");
        } else {
            String[] s = tableNameTemp.trim().split(SPACE);
            if (s.length > 1) {
                tableName = s[0];
                for (String s1 : s) {
                    if (!s1.replaceAll(SPACE, "").equals("") && !s1.equals(tableName)) {
                        tableAlias = s1;
                        break;
                    }
                }
            }
        }


        // 是否取了别名
        String[] split = column.split(",");
        for (String name : split) {
            int as = name.toLowerCase().indexOf(AS);
            String nameSource = "";
            String nameAlias = "";
            if (as > 0) {
                // 截取 别名 例如，name as uName 取 name
                nameAlias = name.substring(as + AS.length()).replaceAll(SPACE, "");
                nameSource = name.substring(0, as).replaceAll(SPACE, "");

                // 如果表取了别名，例如 select c.name as n,n.id from   tb_name   n  where id = 1
                // 截取 name
                if (nameSource.indexOf(tableAlias + ".") >= 0) {
                    nameSource = nameSource.replace(tableAlias + ".", "");
                }
            } else {

                String[] split1 = name.trim().split(SPACE);
                nameSource = split1[0];
                if (split1.length > 1) {
                    for (String s1 : split1) {
                        if (!s1.replaceAll(SPACE, "").equals("") && !s1.equals(nameSource)) {
                            nameAlias = s1;
                            break;
                        }
                    }
                }
                if (nameSource.indexOf(tableAlias + ".") >= 0) {
                    // 如果表取了别名，例如 tb_test as t; select t.id ; 要截取字段 id;
                    nameSource = nameSource.replace(tableAlias + ".", "");
                } else {
                    nameSource = name;
                }
            }

            strings.add(nameSource.trim() + (nameAlias.equals("") ? "" : "," + nameAlias.trim()));
        }

        return strings;
    }
}
